package znet

import (
	"bytes"
	"encoding/binary"
	"errors"
	"zinx/src/utils"
	"zinx/src/ziface"
)

// DataPack 封包拆包类实例，暂时不需要成员
type DataPack struct{}

// NewDataPack 实例化方法
func NewDataPack() *DataPack {
	return &DataPack{}
}

// GetHeadLen 获取包头长度方法
func (dp *DataPack) GetHeadLen() uint32 {
	//Id uint32 + DataLen uint32
	return 8
}

// Pack 封包方法（压缩数据）
func (dp *DataPack) Pack(msg ziface.IMessage) ([]byte, error) {
	//创建一个用于存放bytes字节的缓冲
	dataBuff := bytes.NewBuffer([]byte{})
	//写dataLen,按照LittleEndian序将msg中的信息写入到dataBuff字节缓冲区中
	if err := binary.Write(dataBuff, binary.LittleEndian, msg.GetDataLen()); err != nil {
		return nil, err
	}
	if err := binary.Write(dataBuff, binary.LittleEndian, msg.GetMsgId()); err != nil {
		return nil, err
	}
	if err := binary.Write(dataBuff, binary.LittleEndian, msg.GetData()); err != nil {
		return nil, err
	}
	return dataBuff.Bytes(), nil
}

// Unpack 拆包方法，解压数据
func (dp *DataPack) Unpack(binaryData []byte) (ziface.IMessage, error) {
	//创建一个从输入读取二进制数据的ioReader
	dataBuff := bytes.NewReader(binaryData)
	//只解压head的信息，得到dataLen和msgID,怎么做到的？
	msg := &Message{}
	if err := binary.Read(dataBuff, binary.LittleEndian, &msg.DataLen); err != nil {
		//把dataBuff的数据读到msg中去,因为DataLen为uint32，所以读了8字节的数据就会停
		return nil, err
	}

	if err := binary.Read(dataBuff, binary.LittleEndian, &msg.Id); err != nil {
		return nil, err
	}
	//判断dataLen的长度是否超出我们允许的最大包长度
	if (utils.GlobalObject.MaxPacketSize > 0) && (msg.DataLen > utils.GlobalObject.MaxPacketSize) {
		return nil, errors.New("too large msg data received")
	}
	//只需要head的数据拆包出来就行，然后通过head的长度再从conn读取一次数据
	return msg, nil
}

/*需要注意的是Unpack方法，因为我们从上图可以知道，
我们进行拆包的时候是分两次过程的，第二次是依赖第一次的dataLen结果，
所以Unpack只能解压出包头head的内容，得到msgId 和 dataLen。
之后调用者再根据dataLen继续从io流中读取body中的数据。*/
